package com.example.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.*;
import org.springframework.web.client.RestTemplate;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collections;


/**
 * @author 叮当猫的百宝箱
 * @since 1.0
 */
@Configuration
@Slf4j
public class RestTemplateConfiguration {

    @Bean
    public RestTemplate createRestTemplate() throws Exception {
        // 创建一个忽略 SSL 证书的自定义 HttpClient
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, (x509Certificates, s) -> true).build())
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .build();

        // 使用自定义的 HttpClient 构建请求工厂
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

        // 使用底层的HttpRequestFactory创建BufferingClientHttpRequestFactory
        // 这里主要目的，是为了下面的拦截器读取responseBody后可以重复读
        BufferingClientHttpRequestFactory bufferingRequestFactory = new BufferingClientHttpRequestFactory(requestFactory);
        RestTemplate restTemplate = new RestTemplate(bufferingRequestFactory);
        // 添加请求拦截器
        restTemplate.setInterceptors(Collections.singletonList(new LoggingInterceptor()));
        return restTemplate;
    }

    /**
     * Http请求日志拦截器
     * 主要用来记录发起http请求的参数和响应的参数
     */
    public static class LoggingInterceptor implements ClientHttpRequestInterceptor {

        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            logRequest(request);
            String requestBody = new String(body);
            log.trace("Request body: {}", requestBody);
            ClientHttpResponse response = execution.execute(request, body);
            logResponse(response);
            return response;
        }

        private void logResponse(ClientHttpResponse response) throws IOException {
            log.trace("Response status code: {} ", response.getStatusCode());
            log.trace("Response headers: {} ", response.getHeaders());

            // 记录body
            InputStream body = response.getBody();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();

            IOUtils.copy(body, buffer);
            // Read and log the response body
            String responseBody = buffer.toString(StandardCharsets.UTF_8.name());
            log.trace("Response Body: {} ", responseBody);

            buffer.close();
        }

        private void logRequest(HttpRequest request) {
            log.trace("Request method: {}", request.getMethod());
            log.trace("Request URI: {}", request.getURI());
            log.trace("Request headers: {}", request.getHeaders());
        }
    }

}
